﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Platform.ObjectModel.Design;

namespace Platform.Storage.Impl
{

	/// <summary>
	/// Realiza a pesquisa por um 
	/// </summary>
	internal sealed class MemberAccessFinder : ExpressionVisitor
	{

		public MemberAccessFinder( Type entityType, IQueryResolver resolver )
		{
			this.Resolver = resolver;
			this.EntityType = entityType;
		}

		public IQueryResolver Resolver
		{ get; private set; }

		public MemberAccessTranslation Member
		{ get; private set; }

		public Type EntityType
		{ get; private set; }

		protected override Expression VisitMember( MemberExpression node )
		{
			if ( !node.Type.IsValueType && node.Type != typeof( string ) )
			{
				//if ( node.Type.IsDocument() )
				//{
					Schema schema;
					if ( this.Resolver.TryGetSchema( node.Type, out schema ) )
					{
						var name = schema.QualifiedName; //this.Resolver.GetDataObjectName( node.Type );

						// Se possui um nome, então há um schema cadastrado no repositório
						// então somente pode ser um relacionamento entre dois documentos
						if ( name != null )
						{
							this.Member.RelationSchemaName = name;
							this.Member.RelationType = node.Type;
							this.Member.RelationExpression = node;
							//this.Member.RelationExpression = node.FindRoot();
							return node;
						}
					}
				//}
				//else  
				//{
				//    // Verifica se tem um Formatter
				//    //var schema = this.Resolver.GetSchema( node.Type );

					
				//    throw new NotImplementedException();
				//}
			}

			// Se nessa branch tem um caminho que no final será o parâmetro que 
			// representa a entidade e ainda não foi encontrado algo que indique 
			// que há uma propriedades que é um relacionamento entre dois documentos
			// então ainda continua sendo a propriedade do documento
			if ( node.Has<ParameterExpression>( p => p.Type == this.EntityType )
				&& this.Member.RelationExpression == null )
			{
				this.Member.FieldExpression = node;
			}

			return base.VisitMember( node );
		}

		protected override Expression VisitParameter( ParameterExpression node )
		{
			//if ( node.Type != this.EntityType )
			//    this.Member = new MemberAccessTranslation();
			return base.VisitParameter( node );
		}

		protected override Expression VisitConstant( ConstantExpression node )
		{
			//this.Member = new MemberAccessTranslation();
			return base.VisitConstant( node );
		}

		public MemberAccessTranslation Find( Expression node )
		{
			this.Member = new MemberAccessTranslation();
			this.Visit( node );
			return this.Member;
		}
	}
}
